package com.duang.framework.service;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.duang.framework.cache.Cache;
import com.duang.framework.cache.Node;
import com.duang.framework.config.SystemConfiguration;
import com.duang.framework.dao.BaseDaoTemplate;
import com.duang.framework.dao.DB;
import com.duang.framework.util.IntrospectionUtils;

public class TxManangerInterceptor implements InvocationHandler {

	private BaseService<?> service;
	private BaseDaoTemplate<?> baseDaoTemplate;
	private boolean useCache;
	private Map methodCache;
	private final static Log log = LogFactory
			.getLog(TxManangerInterceptor.class);

	public TxManangerInterceptor(BaseService<?> service) {
		this(service, null, false);
	}

	public TxManangerInterceptor(BaseService<?> service, Map methodCache) {
		this(service, methodCache, true);
	}

	public TxManangerInterceptor(BaseService<?> service, Map methodCache,
			boolean useCache) {
		if (SystemConfiguration.isDedug())
			System.out.println("use cache?" + useCache);
		this.useCache = useCache;
		this.methodCache = methodCache;
		this.service = service;
		this.baseDaoTemplate = (BaseDaoTemplate<?>) this.service.getDao();
	}

	private ConcurrentMap<String, AtomicInteger> stateKeyMap = new ConcurrentHashMap<String, AtomicInteger>();

	public Object handleMethodInvokeUseCache(Method method, Object obj,
			Object[] args) {
		if (SystemConfiguration.isDedug()) {
			System.out.println("invoke method---->" + method);
		}
		Cache cache = (Cache) methodCache.get(IntrospectionUtils
				.getMethodSignKeyInClass(method));
		if (cache == null) {
			return handleMethodInvoke(method, obj, args);
		}
		String cacheKey = ServiceUtils.getMethodCacheKey(args);
		Node node = cache.get(cacheKey);
		if (SystemConfiguration.isDedug()) {
			System.out.println("get Cache---->" + cacheKey + "--->" + node);
		}
		if (node == null) {
			AtomicInteger origin = new AtomicInteger(0);
			AtomicInteger state = stateKeyMap.putIfAbsent(cacheKey, origin);
			// methodTmpState.put(cacheKey, 1);
			if (state == null) {
				if ((node = cache.get(cacheKey)) != null)
					return node.getValue();
				Object returnObj = handleMethodInvoke(method, obj, args);
				node = cache.createNode(cacheKey, returnObj);
				cache.put(node);
				origin.compareAndSet(0, 1);
				stateKeyMap.remove(cacheKey);
				return returnObj;
			} else {
				while (state.get() == 0) {
					Thread.yield();
				}
				return cache.get(cacheKey).getValue();
			}
		}
		return node.getValue();
	}

	public Object handleMethodInvoke(Method method, Object obj, Object[] args) {
		Object returnObj = null;
		try {
			baseDaoTemplate.startTransaction();
			returnObj = method.invoke(obj, args);
			baseDaoTemplate.commit();
		} catch (Exception e) {
			log.error("调用service方法出现异常", e);
			try {
				DB db = baseDaoTemplate.getCurrentDB();
				db.rollback();
				baseDaoTemplate.close(db);
			} catch (NullPointerException e1) {
				log.fatal("baseDaoTemplate.getCurrentDB()空指针异常", e1);
			}
			e.printStackTrace();
		}
		return returnObj;
	}

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		if (useCache)
			return handleMethodInvokeUseCache(method, service, args);
		return handleMethodInvoke(method, service, args);
	}

}
